package huisu;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上，并且使皇后彼此之间不能相互攻击。
 *
 * 给你一个整数 n ，返回所有不同的 n 皇后问题 的解决方案。
 *
 * 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案，该方案中 'Q' 和 '.' 分别代表了皇后和空位。
 *
 */
public class leetCode51_solveNQueens {

    List<List<String>> res = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        //定义棋盘
        char[][] board = new char[n][n];

        //填充空位
        for (char[] c : board) {
            Arrays.fill(c, '.');
        }
        build(board, 0);
        return res;
    }

    //回溯算法
    public void build(char[][] board,int row){

        if(row == board.length){
            List<String> trace = new ArrayList<>();
            for (int i = 0; i < board.length; i++) {
                trace.add(new String(board[i]));
            }
            res.add(trace);
            return;
        }

        int n = board[row].length;

        for (int col = 0; col < n; col++) {
            if(isValid(board,row,col)) {
                board[row][col] = 'Q';

                build(board, row + 1);
                board[row][col] = '.';
            }
        }
    }

    //判断是否可以在board[row][col]放置皇后,为什么只需要左上和右上，
    // 因为每个位置都这么判断就不会重复判断，如果每个节点都判断左上右下，右上左下就没必要了
    public boolean isValid(char[][] board, int row, int col) {
        int n = board.length;
        //检查列是否有皇后冲突
        for (int i = 0; i < n; i++) {
            if (board[i][col] == 'Q') {
                return false;
            }
        }

        //检查右上方是否有皇后冲突
        for (int i = row - 1, j = col + 1; i >=0 && j < n; i--, j++) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }

        //检查左上方是否有皇后冲突
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    List<List<String>> res2 = new ArrayList<>();
    public List<List<String>> solveNQueens2(int n) {
        char[][] board = new char[n][n];
        for (char[] chars : board) {
            Arrays.fill(chars,'.');
        }
        build2(board,0);
        return res2;
    }

    public void build2(char[][] board,int row){
        if(row == board.length){
            List<String> trace = new ArrayList<>();
            for (char[] chars : board) {
                String aa = new String(chars);
                trace.add(aa);
            }
            res2.add(trace);
        }
        int n = board.length;
        for (int i = 0; i < n; i++) {
            if(isValid2(board,row,i)){
                board[row][i] = 'Q';
                build2(board,row + 1);
                board[row][i] = '.';
            }
        }
    }

    public boolean isValid2(char[][] board,int row,int col){
        int n = board.length;
        // 同一列
        for (int i = 0; i < n; i++) {
            if(board[i][col] == 'Q'){
                return false;
            }
        }

        // 左上
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--,j--) {
            if(board[i][j] == 'Q'){
                return false;
            }
        }

        // 右上
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--,j++) {
            if(board[i][j] == 'Q'){
                return false;
            }
        }


        return true;

    }


}
